<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Motivation</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter 1. Coroutine">
<link rel="up" href="../index.html" title="Chapter 1. Coroutine">
<link rel="prev" href="intro.html" title="Introduction">
<link rel="next" href="coroutine.html" title="Coroutine">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="intro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="coroutine.motivation"></a><a class="link" href="motivation.html" title="Motivation">Motivation</a>
</h2></div></div></div>
<p>
      In order to support a broad range of execution control behaviour the coroutine
      types of <span class="emphasis"><em>symmetric_coroutine&lt;&gt;</em></span> and <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;</em></span>
      can be used to <span class="emphasis"><em>escape-and-reenter</em></span> loops, to <span class="emphasis"><em>escape-and-reenter</em></span>
      recursive computations and for <span class="emphasis"><em>cooperative</em></span> multitasking
      helping to solve problems in a much simpler and more elegant way than with
      only a single flow of control.
    </p>
<h4>
<a name="coroutine.motivation.h0"></a>
      <span class="phrase"><a name="coroutine.motivation.event_driven_model"></a></span><a class="link" href="motivation.html#coroutine.motivation.event_driven_model">event-driven
      model</a>
    </h4>
<p>
      The event-driven model is a programming paradigm where the flow of a program
      is determined by events. The events are generated by multiple independent sources
      and an event-dispatcher, waiting on all external sources, triggers callback
      functions (event-handlers) whenever one of those events is detected (event-loop).
      The application is divided into event selection (detection) and event handling.
    </p>
<p>
      <span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/event_model.png" align="middle" alt="event_model"></span>
    </p>
<p>
      The resulting applications are highly scalable, flexible, have high responsiveness
      and the components are loosely coupled. This makes the event-driven model suitable
      for user interface applications, rule-based productions systems or applications
      dealing with asynchronous I/O (for instance network servers).
    </p>
<h4>
<a name="coroutine.motivation.h1"></a>
      <span class="phrase"><a name="coroutine.motivation.event_based_asynchronous_paradigm"></a></span><a class="link" href="motivation.html#coroutine.motivation.event_based_asynchronous_paradigm">event-based
      asynchronous paradigm</a>
    </h4>
<p>
      A classic synchronous console program issues an I/O request (e.g. for user
      input or filesystem data) and blocks until the request is complete.
    </p>
<p>
      In contrast, an asynchronous I/O function initiates the physical operation
      but immediately returns to its caller, even though the operation is not yet
      complete. A program written to leverage this functionality does not block:
      it can proceed with other work (including other I/O requests in parallel) while
      the original operation is still pending. When the operation completes, the
      program is notified. Because asynchronous applications spend less overall time
      waiting for operations, they can outperform synchronous programs.
    </p>
<p>
      Events are one of the paradigms for asynchronous execution, but not all asynchronous
      systems use events. Although asynchronous programming can be done using threads,
      they come with their own costs:
    </p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
          hard to program (traps for the unwary)
        </li>
<li class="listitem">
          memory requirements are high
        </li>
<li class="listitem">
          large overhead with creation and maintenance of thread state
        </li>
<li class="listitem">
          expensive context switching between threads
        </li>
</ul></div>
<p>
      The event-based asynchronous model avoids those issues:
    </p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
          simpler because of the single stream of instructions
        </li>
<li class="listitem">
          much less expensive context switches
        </li>
</ul></div>
<p>
      The downside of this paradigm consists in a sub-optimal program structure.
      An event-driven program is required to split its code into multiple small callback
      functions, i.e. the code is organized in a sequence of small steps that execute
      intermittently. An algorithm that would usually be expressed as a hierarchy
      of functions and loops must be transformed into callbacks. The complete state
      has to be stored into a data structure while the control flow returns to the
      event-loop. As a consequence, event-driven applications are often tedious and
      confusing to write. Each callback introduces a new scope, error callback etc.
      The sequential nature of the algorithm is split into multiple callstacks, making
      the application hard to debug. Exception handlers are restricted to local handlers:
      it is impossible to wrap a sequence of events into a single try-catch block.
      The use of local variables, while/for loops, recursions etc. together with
      the event-loop is not possible. The code becomes less expressive.
    </p>
<p>
      In the past, code using asio's <span class="emphasis"><em>asynchronous operations</em></span>
      was convoluted by callback functions.
    </p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">session</span>
<span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
    <span class="identifier">session</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">&amp;</span> <span class="identifier">io_service</span><span class="special">)</span> <span class="special">:</span>
          <span class="identifier">socket_</span><span class="special">(</span><span class="identifier">io_service</span><span class="special">)</span> <span class="comment">// construct a TCP-socket from io_service</span>
    <span class="special">{}</span>

    <span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">&amp;</span> <span class="identifier">socket</span><span class="special">(){</span>
        <span class="keyword">return</span> <span class="identifier">socket_</span><span class="special">;</span>
    <span class="special">}</span>

    <span class="keyword">void</span> <span class="identifier">start</span><span class="special">(){</span>
        <span class="comment">// initiate asynchronous read; handle_read() is callback-function</span>
        <span class="identifier">socket_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">max_length</span><span class="special">),</span>
            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_read</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
                <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">,</span>
                <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">bytes_transferred</span><span class="special">));</span>
    <span class="special">}</span>

<span class="keyword">private</span><span class="special">:</span>
    <span class="keyword">void</span> <span class="identifier">handle_read</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">error</span><span class="special">,</span>
                     <span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">){</span>
        <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">error</span><span class="special">)</span>
            <span class="comment">// initiate asynchronous write; handle_write() is callback-function</span>
            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">socket_</span><span class="special">,</span>
                <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">bytes_transferred</span><span class="special">),</span>
                <span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_write</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">));</span>
        <span class="keyword">else</span>
            <span class="keyword">delete</span> <span class="keyword">this</span><span class="special">;</span>
    <span class="special">}</span>

    <span class="keyword">void</span> <span class="identifier">handle_write</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">error</span><span class="special">){</span>
        <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">error</span><span class="special">)</span>
            <span class="comment">// initiate asynchronous read; handle_read() is callback-function</span>
            <span class="identifier">socket_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data_</span><span class="special">,</span><span class="identifier">max_length</span><span class="special">),</span>
                <span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">session</span><span class="special">::</span><span class="identifier">handle_read</span><span class="special">,</span><span class="keyword">this</span><span class="special">,</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">error</span><span class="special">,</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">bytes_transferred</span><span class="special">));</span>
        <span class="keyword">else</span>
            <span class="keyword">delete</span> <span class="keyword">this</span><span class="special">;</span>
    <span class="special">}</span>

    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">socket_</span><span class="special">;</span>
    <span class="keyword">enum</span> <span class="special">{</span> <span class="identifier">max_length</span><span class="special">=</span><span class="number">1024</span> <span class="special">};</span>
    <span class="keyword">char</span> <span class="identifier">data_</span><span class="special">[</span><span class="identifier">max_length</span><span class="special">];</span>
<span class="special">};</span>
</pre>
<p>
      In this example, a simple echo server, the logic is split into three member
      functions - local state (such as data buffer) is moved to member variables.
    </p>
<p>
      <span class="bold"><strong>Boost.Asio</strong></span> provides with its new <span class="emphasis"><em>asynchronous
      result</em></span> feature a new framework combining event-driven model and
      coroutines, hiding the complexity of event-driven programming and permitting
      the style of classic sequential code. The application is not required to pass
      callback functions to asynchronous operations and local state is kept as local
      variables. Therefore the code is much easier to read and understand. <a href="#ftn.coroutine.motivation.f0" class="footnote" name="coroutine.motivation.f0"><sup class="footnote">[4]</sup></a>. <span class="emphasis"><em>boost::asio::yield_context</em></span> internally uses
      <span class="bold"><strong>Boost.Coroutine</strong></span>:
    </p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">session</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">io_service</span><span class="special">&amp;</span> <span class="identifier">io_service</span><span class="special">){</span>
    <span class="comment">// construct TCP-socket from io_service</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">socket</span><span class="special">(</span><span class="identifier">io_service</span><span class="special">);</span>

    <span class="keyword">try</span><span class="special">{</span>
        <span class="keyword">for</span><span class="special">(;;){</span>
            <span class="comment">// local data-buffer</span>
            <span class="keyword">char</span> <span class="identifier">data</span><span class="special">[</span><span class="identifier">max_length</span><span class="special">];</span>

            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">;</span>

            <span class="comment">// read asynchronous data from socket</span>
            <span class="comment">// execution context will be suspended until</span>
            <span class="comment">// some bytes are read from socket</span>
            <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">length</span><span class="special">=</span><span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data</span><span class="special">),</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
            <span class="keyword">if</span> <span class="special">(</span><span class="identifier">ec</span><span class="special">==</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">eof</span><span class="special">)</span>
                <span class="keyword">break</span><span class="special">;</span> <span class="comment">//connection closed cleanly by peer</span>
            <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
                <span class="keyword">throw</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">(</span><span class="identifier">ec</span><span class="special">);</span> <span class="comment">//some other error</span>

            <span class="comment">// write some bytes asynchronously</span>
            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span>
                    <span class="identifier">socket</span><span class="special">,</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">data</span><span class="special">,</span><span class="identifier">length</span><span class="special">),</span>
                    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
            <span class="keyword">if</span> <span class="special">(</span><span class="identifier">ec</span><span class="special">==</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">eof</span><span class="special">)</span>
                <span class="keyword">break</span><span class="special">;</span> <span class="comment">//connection closed cleanly by peer</span>
            <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
                <span class="keyword">throw</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">(</span><span class="identifier">ec</span><span class="special">);</span> <span class="comment">//some other error</span>
        <span class="special">}</span>
    <span class="special">}</span> <span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">){</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span><span class="special">&lt;&lt;</span><span class="string">"Exception: "</span><span class="special">&lt;&lt;</span><span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()&lt;&lt;</span><span class="string">"\n"</span><span class="special">;</span>
    <span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
      In contrast to the previous example this one gives the impression of sequential
      code and local data (<span class="emphasis"><em>data</em></span>) while using asynchronous operations
      (<span class="emphasis"><em>async_read()</em></span>, <span class="emphasis"><em>async_write()</em></span>). The
      algorithm is implemented in one function and error handling is done by one
      try-catch block.
    </p>
<h4>
<a name="coroutine.motivation.h2"></a>
      <span class="phrase"><a name="coroutine.motivation.recursive_sax_parsing"></a></span><a class="link" href="motivation.html#coroutine.motivation.recursive_sax_parsing">recursive
      SAX parsing</a>
    </h4>
<p>
      To someone who knows SAX, the phrase "recursive SAX parsing" might
      sound nonsensical. You get callbacks from SAX; you have to manage the element
      stack yourself. If you want recursive XML processing, you must first read the
      entire DOM into memory, then walk the tree.
    </p>
<p>
      But coroutines let you invert the flow of control so you can ask for SAX events.
      Once you can do that, you can process them recursively.
    </p>
<pre class="programlisting"><span class="comment">// Represent a subset of interesting SAX events</span>
<span class="keyword">struct</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
   <span class="identifier">BaseEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;)=</span><span class="keyword">delete</span><span class="special">;</span>
   <span class="identifier">BaseEvent</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">=(</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;)=</span><span class="keyword">delete</span><span class="special">;</span>
<span class="special">};</span>

<span class="comment">// End of document or element</span>
<span class="keyword">struct</span> <span class="identifier">CloseEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
   <span class="comment">// CloseEvent binds (without copying) the TagType reference.</span>
   <span class="identifier">CloseEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">):</span>
       <span class="identifier">mName</span><span class="special">(</span><span class="identifier">name</span><span class="special">)</span>
   <span class="special">{}</span>

   <span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">mName</span><span class="special">;</span>
<span class="special">};</span>

<span class="comment">// Start of document or element</span>
<span class="keyword">struct</span> <span class="identifier">OpenEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">CloseEvent</span><span class="special">{</span>
   <span class="comment">// In addition to CloseEvent's TagType, OpenEvent binds AttributeIterator.</span>
   <span class="identifier">OpenEvent</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
             <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">):</span>
       <span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span>
       <span class="identifier">mAttrs</span><span class="special">(</span><span class="identifier">attrs</span><span class="special">)</span>
   <span class="special">{}</span>

   <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">mAttrs</span><span class="special">;</span>
<span class="special">};</span>

<span class="comment">// text within an element</span>
<span class="keyword">struct</span> <span class="identifier">TextEvent</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">BaseEvent</span><span class="special">{</span>
   <span class="comment">// TextEvent binds the CharIterator.</span>
   <span class="identifier">TextEvent</span><span class="special">(</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">text</span><span class="special">):</span>
       <span class="identifier">mText</span><span class="special">(</span><span class="identifier">text</span><span class="special">)</span>
   <span class="special">{}</span>

   <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">mText</span><span class="special">;</span>
<span class="special">};</span>

<span class="comment">// The parsing coroutine instantiates BaseEvent subclass instances and</span>
<span class="comment">// successively shows them to the main program. It passes a reference so we</span>
<span class="comment">// don't slice the BaseEvent subclass.</span>
<span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>

<span class="keyword">void</span> <span class="identifier">parser</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">){</span>
   <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span> <span class="identifier">xparser</span><span class="special">;</span>
   <span class="comment">// startDocument() will send OpenEvent</span>
   <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">startDocument</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
                                 <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">)</span>
                         <span class="special">{</span>
                             <span class="identifier">sink</span><span class="special">(</span><span class="identifier">OpenEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span><span class="identifier">attrs</span><span class="special">));</span>
                         <span class="special">});</span>
   <span class="comment">// startTag() will likewise send OpenEvent</span>
   <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">startTag</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">,</span>
                            <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">AttributeIterator</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">)</span>
                    <span class="special">{</span>
                        <span class="identifier">sink</span><span class="special">(</span><span class="identifier">OpenEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span><span class="identifier">attrs</span><span class="special">));</span>
                    <span class="special">});</span>
   <span class="comment">// endTag() will send CloseEvent</span>
   <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">endTag</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">)</span>
                  <span class="special">{</span>
                      <span class="identifier">sink</span><span class="special">(</span><span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">));</span>
                  <span class="special">});</span>
   <span class="comment">// endDocument() will likewise send CloseEvent</span>
   <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">endDocument</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="keyword">const</span> <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span><span class="special">&amp;</span> <span class="identifier">name</span><span class="special">)</span>
                       <span class="special">{</span>
                           <span class="identifier">sink</span><span class="special">(</span><span class="identifier">CloseEvent</span><span class="special">(</span><span class="identifier">name</span><span class="special">));</span>
                       <span class="special">});</span>
   <span class="comment">// characters() will send TextEvent</span>
   <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">characters</span><span class="special">([&amp;</span><span class="identifier">sink</span><span class="special">](</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">CharIterator</span><span class="special">&amp;</span> <span class="identifier">text</span><span class="special">)</span>
                      <span class="special">{</span>
                          <span class="identifier">sink</span><span class="special">(</span><span class="identifier">TextEvent</span><span class="special">(</span><span class="identifier">text</span><span class="special">));</span>
                      <span class="special">});</span>
   <span class="keyword">try</span>
   <span class="special">{</span>
       <span class="comment">// parse the document, firing all the above</span>
       <span class="identifier">xparser</span><span class="special">.</span><span class="identifier">parse</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
   <span class="special">}</span>
   <span class="keyword">catch</span> <span class="special">(</span><span class="identifier">xml</span><span class="special">::</span><span class="identifier">Exception</span> <span class="identifier">e</span><span class="special">)</span>
   <span class="special">{</span>
       <span class="comment">// xml::sax::Parser throws xml::Exception. Helpfully translate the</span>
       <span class="comment">// name and provide it as the what() string.</span>
       <span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">runtime_error</span><span class="special">(</span><span class="identifier">exception_name</span><span class="special">(</span><span class="identifier">e</span><span class="special">));</span>
   <span class="special">}</span>
<span class="special">}</span>

<span class="comment">// Recursively traverse the incoming XML document on the fly, pulling</span>
<span class="comment">// BaseEvent&amp; references from 'events'.</span>
<span class="comment">// 'indent' illustrates the level of recursion.</span>
<span class="comment">// Each time we're called, we've just retrieved an OpenEvent from 'events';</span>
<span class="comment">// accept that as a param.</span>
<span class="comment">// Return the CloseEvent that ends this element.</span>
<span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">&amp;</span> <span class="identifier">process</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">events</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;</span> <span class="identifier">context</span><span class="special">,</span>
                          <span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">indent</span><span class="special">=</span><span class="string">""</span><span class="special">){</span>
   <span class="comment">// Capture OpenEvent's tag name: as soon as we advance the parser, the</span>
   <span class="comment">// TagType&amp; reference bound in this OpenEvent will be invalidated.</span>
   <span class="identifier">xml</span><span class="special">::</span><span class="identifier">sax</span><span class="special">::</span><span class="identifier">Parser</span><span class="special">::</span><span class="identifier">TagType</span> <span class="identifier">tagName</span> <span class="special">=</span> <span class="identifier">context</span><span class="special">.</span><span class="identifier">mName</span><span class="special">;</span>
   <span class="comment">// Since the OpenEvent is still the current value from 'events', pass</span>
   <span class="comment">// control back to 'events' until the next event. Of course, each time we</span>
   <span class="comment">// come back we must check for the end of the results stream.</span>
   <span class="keyword">while</span><span class="special">(</span><span class="identifier">events</span><span class="special">()){</span>
       <span class="comment">// Another event is pending; retrieve it.</span>
       <span class="keyword">const</span> <span class="identifier">BaseEvent</span><span class="special">&amp;</span> <span class="identifier">event</span><span class="special">=</span><span class="identifier">events</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
       <span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">*</span> <span class="identifier">oe</span><span class="special">;</span>
       <span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">*</span> <span class="identifier">ce</span><span class="special">;</span>
       <span class="keyword">const</span> <span class="identifier">TextEvent</span><span class="special">*</span> <span class="identifier">te</span><span class="special">;</span>
       <span class="keyword">if</span><span class="special">((</span><span class="identifier">oe</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
           <span class="comment">// When we see OpenEvent, recursively process it.</span>
           <span class="identifier">process</span><span class="special">(</span><span class="identifier">events</span><span class="special">,*</span><span class="identifier">oe</span><span class="special">,</span><span class="identifier">indent</span><span class="special">+</span><span class="string">"    "</span><span class="special">);</span>
       <span class="special">}</span>
       <span class="keyword">else</span> <span class="keyword">if</span><span class="special">((</span><span class="identifier">ce</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">CloseEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
           <span class="comment">// When we see CloseEvent, validate its tag name and then return</span>
           <span class="comment">// it. (This assert is really a check on xml::sax::Parser, since</span>
           <span class="comment">// it already validates matching open/close tags.)</span>
           <span class="identifier">assert</span><span class="special">(</span><span class="identifier">ce</span><span class="special">-&gt;</span><span class="identifier">mName</span> <span class="special">==</span> <span class="identifier">tagName</span><span class="special">);</span>
           <span class="keyword">return</span> <span class="special">*</span><span class="identifier">ce</span><span class="special">;</span>
       <span class="special">}</span>
       <span class="keyword">else</span> <span class="keyword">if</span><span class="special">((</span><span class="identifier">te</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">TextEvent</span><span class="special">*&gt;(&amp;</span><span class="identifier">event</span><span class="special">))){</span>
           <span class="comment">// When we see TextEvent, just report its text, along with</span>
           <span class="comment">// indentation indicating recursion level.</span>
           <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">&lt;&lt;</span><span class="identifier">indent</span><span class="special">&lt;&lt;</span><span class="string">"text: '"</span><span class="special">&lt;&lt;</span><span class="identifier">te</span><span class="special">-&gt;</span><span class="identifier">mText</span><span class="special">.</span><span class="identifier">getText</span><span class="special">()&lt;&lt;</span><span class="string">"'\n"</span><span class="special">;</span>
       <span class="special">}</span>
   <span class="special">}</span>
<span class="special">}</span>

<span class="comment">// pretend we have an XML file of arbitrary size</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">in</span><span class="special">(</span><span class="identifier">doc</span><span class="special">);</span>
<span class="keyword">try</span>
<span class="special">{</span>
   <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">events</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">parser</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">in</span><span class="special">)));</span>
   <span class="comment">// We fully expect at least ONE event.</span>
   <span class="identifier">assert</span><span class="special">(</span><span class="identifier">events</span><span class="special">);</span>
   <span class="comment">// This dynamic_cast&lt;&amp;&gt; is itself an assertion that the first event is an</span>
   <span class="comment">// OpenEvent.</span>
   <span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;</span> <span class="identifier">context</span><span class="special">=</span><span class="keyword">dynamic_cast</span><span class="special">&lt;</span><span class="keyword">const</span> <span class="identifier">OpenEvent</span><span class="special">&amp;&gt;(</span><span class="identifier">events</span><span class="special">.</span><span class="identifier">get</span><span class="special">());</span>
   <span class="identifier">process</span><span class="special">(</span><span class="identifier">events</span><span class="special">,</span> <span class="identifier">context</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span>
<span class="special">{</span>
   <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Parsing error: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="char">'\n'</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
      This problem does not map at all well to communicating between independent
      threads. It makes no sense for either side to proceed independently of the
      other. You want them to pass control back and forth.
    </p>
<p>
      The solution involves a small polymorphic class event hierarchy, to which we're
      passing references. The actual instances are temporaries on the coroutine's
      stack; the coroutine passes each reference in turn to the main logic. Copying
      them as base-class values would slice them.
    </p>
<p>
      If we were trying to let the SAX parser proceed independently of the consuming
      logic, one could imagine allocating event-subclass instances on the heap, passing
      them along on a thread-safe queue of pointers. But that doesn't work either,
      because these event classes bind references passed by the SAX parser. The moment
      the parser moves on, those references become invalid.
    </p>
<p>
      Instead of binding a <span class="emphasis"><em>TagType&amp;</em></span> reference, we could
      store a copy of the <span class="emphasis"><em>TagType</em></span> in <span class="emphasis"><em>CloseEvent</em></span>.
      But that doesn't solve the whole problem. For attributes, we get an <span class="emphasis"><em>AttributeIterator&amp;</em></span>;
      for text we get a <span class="emphasis"><em>CharIterator&amp;</em></span>. Storing a copy of
      those iterators is pointless: once the parser moves on, those iterators are
      invalidated. You must process the attribute iterator (or character iterator)
      during the SAX callback for that event.
    </p>
<p>
      Naturally we could retrieve and store a copy of every attribute and its value;
      we could store a copy of every chunk of text. That would effectively be all
      the text in the document -- a heavy price to pay, if the reason we're using
      SAX is concern about fitting the entire DOM into memory.
    </p>
<p>
      There's yet another advantage to using coroutines. This SAX parser throws an
      exception when parsing fails. With a coroutine implementation, you need only
      wrap the calling code in try/catch.
    </p>
<p>
      With communicating threads, you would have to arrange to catch the exception
      and pass along the exception pointer on the same queue you're using to deliver
      the other events. You would then have to rethrow the exception to unwind the
      recursive document processing.
    </p>
<p>
      The coroutine solution maps very naturally to the problem space.
    </p>
<h4>
<a name="coroutine.motivation.h3"></a>
      <span class="phrase"><a name="coroutine.motivation._same_fringe__problem"></a></span><a class="link" href="motivation.html#coroutine.motivation._same_fringe__problem">'same
      fringe' problem</a>
    </h4>
<p>
      The advantages of suspending at an arbitrary call depth can be seen particularly
      clearly with the use of a recursive function, such as traversal of trees. If
      traversing two different trees in the same deterministic order produces the
      same list of leaf nodes, then both trees have the same fringe.
    </p>
<p>
      <span class="inlinemediaobject"><img src="../../../../../libs/coroutine/doc/images/same_fringe.png" align="middle" alt="same_fringe"></span>
    </p>
<p>
      Both trees in the picture have the same fringe even though the structure of
      the trees is different.
    </p>
<p>
      The same fringe problem could be solved using coroutines by iterating over
      the leaf nodes and comparing this sequence via <span class="emphasis"><em>std::equal()</em></span>.
      The range of data values is generated by function <span class="emphasis"><em>traverse()</em></span>
      which recursively traverses the tree and passes each node's data value to its
      <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::push_type</em></span>
      suspends the recursive computation and transfers the data value to the main
      execution context. <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator</em></span>,
      created from <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type</em></span>,
      steps over those data values and delivers them to <span class="emphasis"><em>std::equal()</em></span>
      for comparison. Each increment of <span class="emphasis"><em>asymmetric_coroutine&lt;&gt;::pull_type::iterator</em></span>
      resumes <span class="emphasis"><em>traverse()</em></span>. Upon return from <span class="emphasis"><em>iterator::operator++()</em></span>,
      either a new data value is available, or tree traversal is finished (iterator
      is invalidated).
    </p>
<p>
      In effect, the coroutine iterator presents a flattened view of the recursive
      data structure.
    </p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">node</span><span class="special">{</span>
    <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">node</span><span class="special">&gt;</span> <span class="identifier">ptr_t</span><span class="special">;</span>

    <span class="comment">// Each tree node has an optional left subtree,</span>
    <span class="comment">// an optional right subtree and a value of its own.</span>
    <span class="comment">// The value is considered to be between the left</span>
    <span class="comment">// subtree and the right.</span>
    <span class="identifier">ptr_t</span>       <span class="identifier">left</span><span class="special">,</span><span class="identifier">right</span><span class="special">;</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">value</span><span class="special">;</span>

    <span class="comment">// construct leaf</span>
    <span class="identifier">node</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">):</span>
        <span class="identifier">left</span><span class="special">(),</span><span class="identifier">right</span><span class="special">(),</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span>
    <span class="special">{}</span>
    <span class="comment">// construct nonleaf</span>
    <span class="identifier">node</span><span class="special">(</span><span class="identifier">ptr_t</span> <span class="identifier">l</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">,</span><span class="identifier">ptr_t</span> <span class="identifier">r</span><span class="special">):</span>
        <span class="identifier">left</span><span class="special">(</span><span class="identifier">l</span><span class="special">),</span><span class="identifier">right</span><span class="special">(</span><span class="identifier">r</span><span class="special">),</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">v</span><span class="special">)</span>
    <span class="special">{}</span>

    <span class="keyword">static</span> <span class="identifier">ptr_t</span> <span class="identifier">create</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">){</span>
        <span class="keyword">return</span> <span class="identifier">ptr_t</span><span class="special">(</span><span class="keyword">new</span> <span class="identifier">node</span><span class="special">(</span><span class="identifier">v</span><span class="special">));</span>
    <span class="special">}</span>

    <span class="keyword">static</span> <span class="identifier">ptr_t</span> <span class="identifier">create</span><span class="special">(</span><span class="identifier">ptr_t</span> <span class="identifier">l</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">v</span><span class="special">,</span><span class="identifier">ptr_t</span> <span class="identifier">r</span><span class="special">){</span>
        <span class="keyword">return</span> <span class="identifier">ptr_t</span><span class="special">(</span><span class="keyword">new</span> <span class="identifier">node</span><span class="special">(</span><span class="identifier">l</span><span class="special">,</span><span class="identifier">v</span><span class="special">,</span><span class="identifier">r</span><span class="special">));</span>
    <span class="special">}</span>
<span class="special">};</span>

<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">root</span><span class="special">){</span>
    <span class="comment">/* --------
         root
         / \
        b   e
       / \
      a   c
     -------- */</span>
    <span class="keyword">return</span> <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
            <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
                <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"a"</span><span class="special">),</span>
                <span class="string">"b"</span><span class="special">,</span>
                <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"c"</span><span class="special">)),</span>
            <span class="identifier">root</span><span class="special">,</span>
            <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"e"</span><span class="special">));</span>
<span class="special">}</span>

<span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&amp;</span> <span class="identifier">root</span><span class="special">){</span>
    <span class="comment">/* --------
         root
         / \
        a   d
           / \
          c   e
       -------- */</span>
    <span class="keyword">return</span> <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
            <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"a"</span><span class="special">),</span>
            <span class="identifier">root</span><span class="special">,</span>
            <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span>
                <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"c"</span><span class="special">),</span>
                <span class="string">"d"</span><span class="special">,</span>
                <span class="identifier">node</span><span class="special">::</span><span class="identifier">create</span><span class="special">(</span><span class="string">"e"</span><span class="special">)));</span>
<span class="special">}</span>

<span class="comment">// recursively walk the tree, delivering values in order</span>
<span class="keyword">void</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">n</span><span class="special">,</span>
              <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
    <span class="keyword">if</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">left</span><span class="special">)</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">left</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
    <span class="identifier">out</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">);</span>
    <span class="keyword">if</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">right</span><span class="special">)</span> <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">n</span><span class="special">-&gt;</span><span class="identifier">right</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
<span class="special">}</span>

<span class="comment">// evaluation</span>
<span class="special">{</span>
    <span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">left_d</span><span class="special">(</span><span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="string">"d"</span><span class="special">));</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">(</span>
        <span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
            <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">left_d</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
        <span class="special">});</span>

    <span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">right_b</span><span class="special">(</span><span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="string">"b"</span><span class="special">));</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">right_b_reader</span><span class="special">(</span>
        <span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
            <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">right_b</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
        <span class="special">});</span>

    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"left tree from d == right tree from b? "</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">equal</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
                            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
                            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">right_b_reader</span><span class="special">))</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">{</span>
    <span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">left_d</span><span class="special">(</span><span class="identifier">create_left_tree_from</span><span class="special">(</span><span class="string">"d"</span><span class="special">));</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">left_d_reader</span><span class="special">(</span>
        <span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
            <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">left_d</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
        <span class="special">});</span>

    <span class="identifier">node</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">right_x</span><span class="special">(</span><span class="identifier">create_right_tree_from</span><span class="special">(</span><span class="string">"x"</span><span class="special">));</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">pull_type</span> <span class="identifier">right_x_reader</span><span class="special">(</span>
        <span class="special">[&amp;](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;::</span><span class="identifier">push_type</span> <span class="special">&amp;</span> <span class="identifier">out</span><span class="special">){</span>
            <span class="identifier">traverse</span><span class="special">(</span><span class="identifier">right_x</span><span class="special">,</span><span class="identifier">out</span><span class="special">);</span>
        <span class="special">});</span>

    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"left tree from d == right tree from x? "</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">equal</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
                            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">left_d_reader</span><span class="special">),</span>
                            <span class="identifier">boost</span><span class="special">::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">right_x_reader</span><span class="special">))</span>
              <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Done"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>

<span class="identifier">output</span><span class="special">:</span>
<span class="identifier">left</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">d</span> <span class="special">==</span> <span class="identifier">right</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">b</span><span class="special">?</span> <span class="keyword">true</span>
<span class="identifier">left</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">d</span> <span class="special">==</span> <span class="identifier">right</span> <span class="identifier">tree</span> <span class="identifier">from</span> <span class="identifier">x</span><span class="special">?</span> <span class="keyword">false</span>
<span class="identifier">Done</span>
</pre>
<h4>
<a name="coroutine.motivation.h4"></a>
      <span class="phrase"><a name="coroutine.motivation.merging_two_sorted_arrays"></a></span><a class="link" href="motivation.html#coroutine.motivation.merging_two_sorted_arrays">merging
      two sorted arrays</a>
    </h4>
<p>
      This example demonstrates how symmetric coroutines merge two sorted arrays.
    </p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">merge</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">a</span><span class="special">,</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">){</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">c</span><span class="special">;</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">idx_a</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier">idx_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="special">*</span><span class="identifier">other_a</span><span class="special">=</span><span class="number">0</span><span class="special">,*</span><span class="identifier">other_b</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>

    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_a</span><span class="special">(</span>
        <span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
            <span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_a</span><span class="special">&lt;</span><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">()){</span>
                <span class="keyword">if</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">]&lt;</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">])</span>    <span class="comment">// test if element in array b is less than in array a</span>
                    <span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_b</span><span class="special">);</span>     <span class="comment">// yield to coroutine coro_b</span>
                <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
            <span class="special">}</span>
            <span class="comment">// add remaining elements of array b</span>
            <span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_b</span><span class="special">&lt;</span><span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
                <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span>
        <span class="special">});</span>

    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">call_type</span> <span class="identifier">coro_b</span><span class="special">(</span>
        <span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">symmetric_coroutine</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">yield_type</span><span class="special">&amp;</span> <span class="identifier">yield</span><span class="special">){</span>
            <span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_b</span><span class="special">&lt;</span><span class="identifier">b</span><span class="special">.</span><span class="identifier">size</span><span class="special">()){</span>
                <span class="keyword">if</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">]&lt;</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">])</span>    <span class="comment">// test if element in array a is less than in array b</span>
                    <span class="identifier">yield</span><span class="special">(*</span><span class="identifier">other_a</span><span class="special">);</span>     <span class="comment">// yield to coroutine coro_a</span>
                <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">b</span><span class="special">[</span><span class="identifier">idx_b</span><span class="special">++]);</span> <span class="comment">// add element to final array</span>
            <span class="special">}</span>
            <span class="comment">// add remaining elements of array a</span>
            <span class="keyword">while</span><span class="special">(</span><span class="identifier">idx_a</span><span class="special">&lt;</span><span class="identifier">a</span><span class="special">.</span><span class="identifier">size</span><span class="special">())</span>
                <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a</span><span class="special">[</span><span class="identifier">idx_a</span><span class="special">++]);</span>
        <span class="special">});</span>


    <span class="identifier">other_a</span><span class="special">=&amp;</span><span class="identifier">coro_a</span><span class="special">;</span>
    <span class="identifier">other_b</span><span class="special">=&amp;</span><span class="identifier">coro_b</span><span class="special">;</span>

    <span class="identifier">coro_a</span><span class="special">();</span> <span class="comment">// enter coroutine-fn of coro_a</span>

    <span class="keyword">return</span> <span class="identifier">c</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<h4>
<a name="coroutine.motivation.h5"></a>
      <span class="phrase"><a name="coroutine.motivation.chaining_coroutines"></a></span><a class="link" href="motivation.html#coroutine.motivation.chaining_coroutines">chaining
      coroutines</a>
    </h4>
<p>
      This code shows how coroutines could be chained.
    </p>
<pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">coroutines</span><span class="special">::</span><span class="identifier">asymmetric_coroutine</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span> <span class="identifier">coro_t</span><span class="special">;</span>

<span class="comment">// deliver each line of input stream to sink as a separate string</span>
<span class="keyword">void</span> <span class="identifier">readlines</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">){</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">line</span><span class="special">;</span>
    <span class="keyword">while</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">getline</span><span class="special">(</span><span class="identifier">in</span><span class="special">,</span><span class="identifier">line</span><span class="special">))</span>
        <span class="identifier">sink</span><span class="special">(</span><span class="identifier">line</span><span class="special">);</span>
<span class="special">}</span>

<span class="keyword">void</span> <span class="identifier">tokenize</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span> <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
    <span class="comment">// This tokenizer doesn't happen to be stateful: you could reasonably</span>
    <span class="comment">// implement it with a single call to push each new token downstream. But</span>
    <span class="comment">// I've worked with stateful tokenizers, in which the meaning of input</span>
    <span class="comment">// characters depends in part on their position within the input line.</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">line</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">::</span><span class="identifier">size_type</span> <span class="identifier">pos</span><span class="special">=</span><span class="number">0</span><span class="special">;</span>
        <span class="keyword">while</span><span class="special">(</span><span class="identifier">pos</span><span class="special">&lt;</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()){</span>
            <span class="keyword">if</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]==</span><span class="char">'"'</span><span class="special">){</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">;</span>
                <span class="special">++</span><span class="identifier">pos</span><span class="special">;</span>              <span class="comment">// skip open quote</span>
                <span class="keyword">while</span><span class="special">(</span><span class="identifier">pos</span><span class="special">&lt;</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()&amp;&amp;</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]!=</span><span class="char">'"'</span><span class="special">)</span>
                    <span class="identifier">token</span><span class="special">+=</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++];</span>
                <span class="special">++</span><span class="identifier">pos</span><span class="special">;</span>              <span class="comment">// skip close quote</span>
                <span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>        <span class="comment">// pass token downstream</span>
            <span class="special">}</span> <span class="keyword">else</span> <span class="keyword">if</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">isspace</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">])){</span>
                <span class="special">++</span><span class="identifier">pos</span><span class="special">;</span>              <span class="comment">// outside quotes, ignore whitespace</span>
            <span class="special">}</span> <span class="keyword">else</span> <span class="keyword">if</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">])){</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">;</span>
                <span class="keyword">while</span> <span class="special">(</span><span class="identifier">pos</span> <span class="special">&lt;</span> <span class="identifier">line</span><span class="special">.</span><span class="identifier">length</span><span class="special">()</span> <span class="special">&amp;&amp;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">]))</span>
                    <span class="identifier">token</span> <span class="special">+=</span> <span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++];</span>
                <span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>        <span class="comment">// pass token downstream</span>
            <span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>                <span class="comment">// punctuation</span>
                <span class="identifier">sink</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">(</span><span class="number">1</span><span class="special">,</span><span class="identifier">line</span><span class="special">[</span><span class="identifier">pos</span><span class="special">++]));</span>
            <span class="special">}</span>
        <span class="special">}</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="keyword">void</span> <span class="identifier">only_words</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
        <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">token</span><span class="special">.</span><span class="identifier">empty</span><span class="special">()</span> <span class="special">&amp;&amp;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">isalpha</span><span class="special">(</span><span class="identifier">token</span><span class="special">[</span><span class="number">0</span><span class="special">]))</span>
            <span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="keyword">void</span> <span class="identifier">trace</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span><span class="special">&amp;</span> <span class="identifier">sink</span><span class="special">,</span> <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">){</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">source</span><span class="special">){</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"trace: '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">token</span> <span class="special">&lt;&lt;</span> <span class="string">"'\n"</span><span class="special">;</span>
        <span class="identifier">sink</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="keyword">struct</span> <span class="identifier">FinalEOL</span><span class="special">{</span>
    <span class="special">~</span><span class="identifier">FinalEOL</span><span class="special">(){</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
    <span class="special">}</span>
<span class="special">};</span>

<span class="keyword">void</span> <span class="identifier">layout</span><span class="special">(</span><span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span><span class="special">&amp;</span> <span class="identifier">source</span><span class="special">,</span><span class="keyword">int</span> <span class="identifier">num</span><span class="special">,</span><span class="keyword">int</span> <span class="identifier">width</span><span class="special">){</span>
    <span class="comment">// Finish the last line when we leave by whatever means</span>
    <span class="identifier">FinalEOL</span> <span class="identifier">eol</span><span class="special">;</span>

    <span class="comment">// Pull values from upstream, lay them out 'num' to a line</span>
    <span class="keyword">for</span> <span class="special">(;;){</span>
        <span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special">&lt;</span> <span class="identifier">num</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">){</span>
            <span class="comment">// when we exhaust the input, stop</span>
            <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">source</span><span class="special">)</span> <span class="keyword">return</span><span class="special">;</span>

            <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setw</span><span class="special">(</span><span class="identifier">width</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">source</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
            <span class="comment">// now that we've handled this item, advance to next</span>
            <span class="identifier">source</span><span class="special">();</span>
        <span class="special">}</span>
        <span class="comment">// after 'num' items, line break</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="comment">// For example purposes, instead of having a separate text file in the</span>
<span class="comment">// local filesystem, construct an istringstream to read.</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">data</span><span class="special">(</span>
    <span class="string">"This is the first line.\n"</span>
    <span class="string">"This, the second.\n"</span>
    <span class="string">"The third has \"a phrase\"!\n"</span>
    <span class="special">);</span>

<span class="special">{</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nfilter:\n"</span><span class="special">;</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">tokenizer</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tracer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">trace</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">filter</span><span class="special">)));</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">tracer</span><span class="special">){</span>
        <span class="comment">// just iterate, we're already pulling through tracer</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="special">{</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nlayout() as coroutine::push_type:\n"</span><span class="special">;</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">tokenizer</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">layout</span><span class="special">,</span> <span class="identifier">_1</span><span class="special">,</span> <span class="number">5</span><span class="special">,</span> <span class="number">15</span><span class="special">));</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">filter</span><span class="special">){</span>
        <span class="identifier">writer</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
    <span class="special">}</span>
<span class="special">}</span>

<span class="special">{</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"\nfiltering output:\n"</span><span class="special">;</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">istringstream</span> <span class="identifier">infile</span><span class="special">(</span><span class="identifier">data</span><span class="special">);</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">reader</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">readlines</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">infile</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">pull_type</span> <span class="identifier">tokenizer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">tokenize</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">reader</span><span class="special">)));</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">writer</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">layout</span><span class="special">,</span><span class="identifier">_1</span><span class="special">,</span><span class="number">5</span><span class="special">,</span><span class="number">15</span><span class="special">));</span>
    <span class="comment">// Because of the symmetry of the API, we can use any of these</span>
    <span class="comment">// chaining functions in a push_type coroutine chain as well.</span>
    <span class="identifier">coro_t</span><span class="special">::</span><span class="identifier">push_type</span> <span class="identifier">filter</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">only_words</span><span class="special">,</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">writer</span><span class="special">),</span><span class="identifier">_1</span><span class="special">));</span>
    <span class="identifier">BOOST_FOREACH</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">token</span><span class="special">,</span><span class="identifier">tokenizer</span><span class="special">){</span>
        <span class="identifier">filter</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
    <span class="special">}</span>
<span class="special">}</span>
</pre>
<div class="footnotes">
<br><hr style="width:100; text-align:left;margin-left: 0">
<div id="ftn.coroutine.motivation.f0" class="footnote"><p><a href="#coroutine.motivation.f0" class="para"><sup class="para">[4] </sup></a>
        Christopher Kohlhoff, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3964.pdf" target="_top">N3964
        - Library Foundations for Asynchronous Operations, Revision 1</a>
      </p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright © 2009 Oliver Kowalke<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
      </p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="intro.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="coroutine.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>
